<template>
    <div id="image-recognition">
        <!-- “加载中” -->
        <div id="loadingDiv" v-if="isLoading">
            <!-- “加载中”的动画 -->
            <u-loading mode="flower" textSize="30" size="50"></u-loading>
            <span id="loading">识别中</span>
        </div>
        <!-- 饼图图表，如果isShowPieChart为true，则显示饼图 -->
        <div class="charts-box" v-if="isShowPieChart === true">
            <qiun-data-charts
                type="pie"
                :opts="pieChartConfiguration"
                :chartData="chartData"
                :canvas2d="true"
                canvasId="pAzTHlVRnHaoVtJWFIZJuUQNPvYkbZDS"
            />
        </div>
        <!-- 柱状图，如果isShowPieChart为false，则显示柱形图 -->
        <div class="charts-box" v-if="isShowPieChart === false">
            <qiun-data-charts
                type="column"
                :opts="histogramConfiguration"
                :chartData="chartData"
                :canvas2d="true"
                canvasId="vWJShxzdJLMFnWxMyIWEvphGyiAgqKWm"
            />
        </div>
        <!-- gutter：元素之间的间距 -->
        <u-row gutter="10">
            <!-- span：占用的空间比例 -->
            <u-col span="9">
                <!-- 使用uView里面内置的上外边距class，值为20 -->
                <div class="u-margin-top-20">
                    <u-input
                        placeholder="请输入链接"
                        id="inputUrl"
                        v-model.trim="imageUrl"
                        type="text"
                        :border="true"
                        border-color="#2979ff"
                        :clearable="true"
                    />
                </div>
            </u-col>
            <u-col span="3">
                <div class="u-margin-top-15"><u-button type="primary" @click="identifyImage">链接识别</u-button></div>
            </u-col>
        </u-row>

        <u-row gutter="10">
            <u-col span="3">
                <div class="u-margin-top-15"><u-button type="primary" @click="takePhoto">拍照识别</u-button></div>
            </u-col>
            <u-col span="4">
                <div class="u-margin-top-15">
                    <u-button type="primary" @click="switchingChartTypes" v-if="isShowPieChart === true">
                        切换为柱状图
                    </u-button>
                </div>
                <div class="u-margin-top-15">
                    <u-button type="primary" @click="switchingChartTypes" v-if="isShowPieChart === false">
                        切换为饼状图
                    </u-button>
                </div>
            </u-col>
            <u-col span="3">
                <div class="u-margin-top-15"><u-button type="primary" @click="photoOcr">识别文字</u-button></div>
            </u-col>
        </u-row>

        <div>
            <!-- fade：淡入动画；duration：动画的过渡时间；mode="aspectFit"表示能按图片比例进行缩放并完整显示-->
            <u-image
                width="100%"
                height="360rpx"
                mode="aspectFit"
                :src="showPhotoSrc"
                :fade="true"
                duration="450"
            ></u-image>
        </div>
    </div>
</template>

<script>
// 导入此图片识别项目封装的方法
import {
    histogramChartData,
    histogramConfiguration,
    pieChartConfiguration,
    pieChartData
} from "../jsFunction/imageData";

export default {
    name: "image-recognition",
    data() {
        return {
            // 服务器地址（这里是我自己的服务器的域名）
            serverUrl: "https://thinkphp.hyy666.top/",
            // 图片的地址（去除两边空格）
            imageUrl: "",
            // 展示图片用的，用于src属性
            showPhotoSrc: "",
            // 通过相机或本地图片，识别后Base64编码好的结果
            imageBase64: null,
            // 存放识别结果的数组
            imageList: [],
            pieData: {},
            // 是否正在加载
            isLoading: false,
            // 是否识别成功（用于做判断，未识别之前不能使用某些功能按钮）
            isIdentifySuccess: false,
            // 识别类型
            identifyType: "",

            // 是否要显示饼图
            isShowPieChart: true,
            // 用于饼图的数据
            chartData: {},
            // 饼图的属性设置（这里是ES6写法，属性和值都是一样的，此变量从“jsFunction目录下的imageData.js”文件导入
            pieChartConfiguration,
            // 柱状图的配置信息
            histogramConfiguration
        };
    },
    methods: {
        // 对传入的图片URL进行识别
        identifyImage() {
            if (this.imageUrl !== "") {
                // 将“是否正在加载”改为true，开始执行“加载中”的动画
                this.isLoading = true;
                // 在uni-app中，用axios不兼容，而uni的request()方法时原生的，推荐用这个
                uni.request({
                    method: "post",
                    data: { imageUrl: this.imageUrl },
                    // 后台接口的url
                    url: `${this.serverUrl}Image/imageIdentification`,
                    success: res => {
                        // 提取出重要的内容
                        let result = res.data.result;
                        if (result === undefined) {
                            uni.showToast({
                                title: "无法识别此链接",
                                // 使用icon:"none"，可以解除字数的限制，但会把图标隐藏掉
                                // image可以使用自定义的图片，作为提示
                                image: "/static/error.png"
                            });
                        } else {
                            // 识别的类型
                            this.identifyType = "URL识别";
                            // 展示饼图
                            this.isShowPieChart = true;
                            // 将图片的src赋值到data，给图片框用于显示（imageUrl是输入的URL）
                            this.showPhotoSrc = this.imageUrl;
                            // 将结果数据赋值给data的变量
                            this.imageList = result;
                            // 重新赋值，更新数据，要记得进行先进行JSON解析，然后转为JSON字符串
                            this.chartData = pieChartData(result);
                            // isIdentifySuccess为true表示识别成功
                            this.isIdentifySuccess = true;
                            uni.showToast({
                                title: "识别成功",
                                duration: 2000
                            });
                        }
                        // 加载完毕就关闭动画
                        this.isLoading = false;
                        // 并清空输入框
                        this.imageUrl = "";
                    },
                    fail: () => {
                        uni.showToast({
                            title: "服务器未开启",
                            // 使用icon:"none"，可以解除字数的限制，但会把图标隐藏掉
                            // image可以使用自定义的图片，作为提示
                            image: "/static/error.png"
                        });
                        // 关闭动画
                        this.isLoading = false;
                    }
                });
            } else {
                uni.showToast({
                    title: "图片链接不能空",
                    // 使用icon:"none"，可以解除字数的限制，但会把图标隐藏掉
                    // image可以使用自定义的图片，作为提示
                    image: "/static/error.png"
                });
            }
        },
        // 拍照
        takePhoto() {
            // 调用微信小程序拍照、选择相册的功能
            uni.chooseImage({
                count: 1,
                sizeType: ["original", "compressed"],
                // 这要注意，camera掉拍照，album是打开手机相册
                sourceType: ["camera", "album"],
                success: res => {
                    /*拍摄或选择照片完毕后，会自动缓存到一个缓存目录，这里能获取此照片的路径，因为图片有时不止一张，
                    所以格式默认为数组，但这里只取一张*/
                    this.showPhotoSrc = res.tempFilePaths[0];
                    // 如果选择完毕
                    if (res.errMsg === "chooseImage:ok") {
                        // 将“是否正在加载”改为true，开始执行“加载中”的动画
                        this.isLoading = true;
                        uni.getFileSystemManager().readFile({
                            filePath: this.showPhotoSrc,
                            // 编码格式为Base64，将图片转换为Base64编码的字符串
                            encoding: "base64",
                            success: res => {
                                // 将编码后的结果存储到data的变量中
                                this.imageBase64 = res.data;
                                uni.request({
                                    method: "post",
                                    // 将Base64编码传给后端
                                    data: { imageBase64: res.data },
                                    // 后台接口的url
                                    url: `${this.serverUrl}Image/takeImage`,
                                    success: res => {
                                        // 提取出重要的内容，即识别结果
                                        let result = res.data.result;
                                        if (result === undefined) {
                                            uni.showToast({
                                                title: "无法识别",
                                                // 使用icon:"none"，可以解除字数的限制，但会把图标隐藏掉
                                                // image可以使用自定义的图片，作为提示
                                                image: "/static/error.png"
                                            });
                                        } else {
                                            // 识别的类型
                                            this.identifyType = "拍照识别";
                                            // 展示饼图
                                            this.isShowPieChart = true;
                                            // 将结果赋值给data中的变量
                                            this.imageList = result;
                                            // 重新赋值，更新数据，要记得进行先进行JSON解析，然后转为JSON字符串
                                            this.chartData = pieChartData(result);
                                            // isIdentifySuccess为true表示识别成功
                                            this.isIdentifySuccess = true;
                                            uni.showToast({
                                                title: "识别成功",
                                                duration: 2000
                                            });
                                        }
                                        // 加载完毕就关闭动画
                                        this.isLoading = false;
                                    },
                                    fail: () => {
                                        uni.showToast({
                                            title: "服务器未开启",
                                            // 使用icon:"none"，可以解除字数的限制，但会把图标隐藏掉
                                            // image可以使用自定义的图片，作为提示
                                            image: "/static/error.png"
                                        });
                                        // 关闭动画
                                        this.isLoading = false;
                                    }
                                });
                            }
                        });
                    }
                }
            });
        },
        // 切换图表类型
        switchingChartTypes() {
            // 只有当识别成功时，才能切换图表
            if (this.isIdentifySuccess === true) {
                // 如果是饼图
                if (this.isShowPieChart === true) {
                    // 就将数据赋值为柱状图用的数据
                    this.chartData = histogramChartData(this.imageList);
                }
                // 如果是柱状图
                else {
                    // 将data中的数据赋值到一个变量中
                    this.chartData = pieChartData(this.imageList);
                }
                // 切换图表
                this.isShowPieChart = !this.isShowPieChart;
            } else {
                uni.showToast({
                    title: "识别后才能切换",
                    // 使用icon:"none"，可以解除字数的限制，但会把图标隐藏掉
                    // image可以使用自定义的图片，作为提示
                    image: "/static/error.png"
                });
            }
        },
        // 图像文字识别
        photoOcr() {
            // 只有当识别成功时，才能进行文字识别
            if (this.isIdentifySuccess === true) {
                // 将“是否正在加载”改为true，开始执行“加载中”的动画
                this.isLoading = true;
                if (this.identifyType === "URL识别") {
                    uni.request({
                        method: "POST",
                        data: { imageUrl: this.showPhotoSrc },
                        // 后台接口的url
                        url: `${this.serverUrl}Image/urlOcr`,
                        success: res => {
                            // 提取出重要的内容，words_result是识别的结果，以数组的形式存在
                            let result = res.data.words_result;
                            if (result.length === 0) {
                                uni.showToast({
                                    title: "图中没有文字",
                                    // 使用icon:"none"，可以解除字数的限制，但会把图标隐藏掉
                                    // image可以使用自定义的图片，作为提示
                                    image: "/static/error.png"
                                });
                            } else {
                                // 准备复制到剪贴板的内容
                                let clipboardContent = "";
                                // 将数组里的每一个内容都拼接到一个变量上，并做换行处理
                                result.forEach(element => {
                                    clipboardContent += `${element.words}\n`;
                                });
                                // 识别成功后，将内容复制到剪贴板
                                uni.setClipboardData({
                                    data: clipboardContent.trim()
                                });
                            }
                            // 加载完毕就关闭动画
                            this.isLoading = false;
                        },
                        fail: () => {
                            uni.showToast({
                                title: "服务器未开启",
                                // 使用icon:"none"，可以解除字数的限制，但会把图标隐藏掉
                                // image可以使用自定义的图片，作为提示
                                image: "/static/error.png"
                            });
                            // 关闭动画
                            this.isLoading = false;
                        }
                    });
                } else if (this.identifyType === "拍照识别") {
                    // 将“是否正在加载”改为true，开始执行“加载中”的动画
                    this.isLoading = true;
                    uni.request({
                        method: "post",
                        // 将之前存储的Base64编码传给后端
                        data: { imageBase64: this.imageBase64 },
                        // 后台接口的url
                        url: `${this.serverUrl}Image/cameraOcr`,
                        success: res => {
                            // 提取出重要的内容，即识别结果
                            let result = res.data.words_result;
                            if (result.length === 0) {
                                uni.showToast({
                                    title: "图中没有文字",
                                    // 使用icon:"none"，可以解除字数的限制，但会把图标隐藏掉
                                    // image可以使用自定义的图片，作为提示
                                    image: "/static/error.png"
                                });
                            } else {
                                // 准备复制到剪贴板的内容
                                let clipboardContent = "";
                                // 将数组里的每一个内容都拼接到一个变量上
                                result.forEach(element => {
                                    clipboardContent += `${element.words}\n`;
                                });
                                // 识别成功后，将内容复制到剪贴板
                                uni.setClipboardData({
                                    data: clipboardContent.trim()
                                });
                            }
                            // 加载完毕就关闭动画
                            this.isLoading = false;
                        },
                        fail: () => {
                            uni.showToast({
                                title: "服务器未开启",
                                // 使用icon:"none"，可以解除字数的限制，但会把图标隐藏掉
                                // image可以使用自定义的图片，作为提示
                                image: "/static/error.png"
                            });
                            // 关闭动画
                            this.isLoading = false;
                        }
                    });
                }
            } else {
                uni.showToast({
                    title: "请先图像识别",
                    // 使用icon:"none"，可以解除字数的限制，但会把图标隐藏掉
                    // image可以使用自定义的图片，作为提示
                    image: "/static/error.png"
                });
            }
        }
    }
};
</script>

<style scoped>
/* 加载动画的div */
#loadingDiv {
    text-align: center;
}

/* “识别中”的文字 */
#loading {
    color: #909399;
}

/* 图表的div */
.charts-box {
    width: 100%;
    height: 100%;
    margin-top: 20rpx;
}
</style>
